//Copyright (c) Microsoft Corporation.  All rights reserved.

using System;
using System.Text;
using System.Collections.Generic;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace Eas.WebCrawler.Test.PlugIns {
    /// <summary>
    /// Summary description for TemporaryStorageTest
    /// </summary>
    [TestClass]
    public class TemporaryStorageTest {

        private static TestContext _Context;
        private static NMock2.Mockery _Mockery;
        //        private static Eas.WebCrawler.Interfaces.WebCrawlerResponse _Response;
        private const string textContent = "text/html";
        private const string nonTextContent = "video/mpg";

        public TemporaryStorageTest() {

        }

        #region Additional test attributes
        //
        // You can use the following additional attributes as you write your tests:
        //
        // Use ClassInitialize to run code before running the first test in the class
        // [ClassInitialize()]
        // public static void MyClassInitialize(TestContext testContext) { }
        //
        // Use ClassCleanup to run code after all tests in a class have run
        // [ClassCleanup()]
        // public static void MyClassCleanup() { }
        //
        // Use TestInitialize to run code before running each test 
        [TestInitialize()]
        public void MyTestInitialize() {
            TestDirectoryHelper.Setup();

            _Mockery = new NMock2.Mockery();
            //            _Response = _Mockery.NewMock<Eas.WebCrawler.Interfaces.WebCrawlerResponse>();

            _Context = new TestContext();
            _Context.DelegatedContext = _Mockery.NewMock<Eas.WebCrawler.Interfaces.WebCrawlerContext>();
        }

        //
        // Use TestCleanup to run code after each test has run
        [TestCleanup()]
        public void MyTestCleanup() {
            _Mockery.VerifyAllExpectationsHaveBeenMet();
            //_Response = null;
            _Context.Dispose();
            _Context = null;
            _Mockery.Dispose();
            _Mockery = null;

            TestDirectoryHelper.TearDown();
        }

        //
        #endregion

        [TestMethod]
        [ExpectedException(typeof(System.ArgumentOutOfRangeException))]
        /// <summary>Executes the TestFileStorageWithBadDirectory test, in which the <seealso cref="System.ArgumentOutOfRangeException"/> exception should be thrown during a succesfull test run.</summary>
        public void TestFileStorageWithBadDirectory() {
            string dir = "c:\\" + new Guid().ToString();
            Eas.WebCrawler.PlugIns.TemporaryStorage.FileStorageFactory factory = new Eas.WebCrawler.PlugIns.TemporaryStorage.FileStorageFactory(dir);
        }

        [TestMethod]
        /// <summary>Executes the TestMemoryStorage test.</summary>
        public void TestMemoryStorage() {

            TestStorage(new Eas.WebCrawler.PlugIns.TemporaryStorage.MemoryStorageFactory(), null);
        }

        [TestMethod]
        /// <summary>Executes the TestFileStorageSimple test.</summary>
        public void TestFileStorageSimple() {
            Eas.WebCrawler.PlugIns.TemporaryStorage.FileStorageFactory factory = new Eas.WebCrawler.PlugIns.TemporaryStorage.FileStorageFactory(TestDirectoryHelper.TargetDir.FullName);
            TestStorage(factory, null);
            Assert.AreEqual<string>(TestDirectoryHelper.TargetDir.FullName, factory.StorageDirectory.FullName);
        }

        [TestMethod]
        /// <summary>Executes the TestFileDeletionAfterFileStorage test.</summary>
        public void TestFileDeletionAfterFileStorage() {
            string filename = TestDirectoryHelper.Name(TestDirectory.Target, "TestFileDeletionAfterFileStorage.txt");
            using (Eas.WebCrawler.PlugIns.TemporaryStorage.FileStorage storage = new Eas.WebCrawler.PlugIns.TemporaryStorage.FileStorage(filename)) {
                Assert.AreEqual<string>(filename, storage.FileName);
                string testString = "Hello World!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!";
                byte[] bytes = new byte[] { 5, 4, 3, 2, 1 };
                using (System.IO.TextWriter writer = storage.GetTextWriter()) {
                    writer.Write(testString);
                }
                using (System.IO.TextReader reader = storage.GetTextReader()) {
                    string newString = reader.ReadToEnd();
                    Assert.AreEqual<string>(testString, newString);
                }
            }
            Assert.IsFalse(System.IO.File.Exists(filename));
        }

        [TestMethod]
        /// <summary>Executes the TestMemoryTextMultipleReaders test.</summary>
        public void TestMemoryTextMultipleReaders() {
            string test = "hello world";
            using (Eas.WebCrawler.PlugIns.TemporaryStorage.MemoryStorage storage = new Eas.WebCrawler.PlugIns.TemporaryStorage.MemoryStorage()) {
                using (System.IO.TextWriter w = storage.GetTextWriter()) {
                    w.Write(test);
                }
                using (System.IO.TextReader r = storage.GetTextReader()) {
                    string s = r.ReadToEnd();
                    Assert.AreEqual<string>(test, s);
                }
                using (System.IO.TextReader r = storage.GetTextReader()) {
                    string s = r.ReadToEnd();
                    Assert.AreEqual<string>(test, s);
                }
            }

        }

        [TestMethod]
        /// <summary>Executes the TesFileTextMultipleReaders test.</summary>
        public void TestFileTextMultipleReaders() {
            string test = "hello world";
            string filename = TestDirectoryHelper.Name(TestDirectory.Target, "TestFileDeletionAfterFileStorage.txt");

            using (Eas.WebCrawler.PlugIns.TemporaryStorage.FileStorage storage = new Eas.WebCrawler.PlugIns.TemporaryStorage.FileStorage(filename)) {
                using (System.IO.TextWriter w = storage.GetTextWriter()) {
                    w.Write(test);
                }
                using (System.IO.TextReader r = storage.GetTextReader()) {
                    string s = r.ReadToEnd();
                    Assert.AreEqual<string>(test, s);
                }
                using (System.IO.TextReader r = storage.GetTextReader()) {
                    string s = r.ReadToEnd();
                    Assert.AreEqual<string>(test, s);
                }
            }
        }

        [TestMethod]
        /// <summary>Executes the TestConditionalStorage test.</summary>
        public void TestConditionalStorage() {

            Eas.WebCrawler.PlugIns.TemporaryStorage.MemoryStorageFactory memoryStorageFactory = new Eas.WebCrawler.PlugIns.TemporaryStorage.MemoryStorageFactory();
            Eas.WebCrawler.PlugIns.TemporaryStorage.FileStorageFactory fileStorageFactory = new Eas.WebCrawler.PlugIns.TemporaryStorage.FileStorageFactory(TestDirectoryHelper.TargetDir.FullName);

            Eas.WebCrawler.PlugIns.TemporaryStorage.IsTextResponseConditionalFactory conditionalFactory = new Eas.WebCrawler.PlugIns.TemporaryStorage.IsTextResponseConditionalFactory(memoryStorageFactory, fileStorageFactory);

            conditionalFactory.Initialize(_Context);
            _Context._Events.Fire_Starting();

            TestProcessingState processingState = new TestProcessingState(4);
            TestStorageType(conditionalFactory, processingState, typeof(Eas.WebCrawler.PlugIns.TemporaryStorage.MemoryStorage));

            processingState._IsTextResponse = false;
            TestStorageType(conditionalFactory, processingState, typeof(Eas.WebCrawler.PlugIns.TemporaryStorage.FileStorage));
            _Context._Events.Fire_Stopped();
        }

        private void TestStorageType(Eas.WebCrawler.Interfaces.TemporaryStorageFactory factory, Eas.WebCrawler.Interfaces.ProcessingState processingState, System.Type type) {
            using (Eas.WebCrawler.Interfaces.TemporaryStorage store = factory.Create(processingState)) {
                Assert.IsInstanceOfType(store, type);
            }
        }

        private void TestStorage(Eas.WebCrawler.Interfaces.TemporaryStorageFactory factory, Eas.WebCrawler.Interfaces.ProcessingState processingState) {
            factory.Initialize(_Context);
            _Context._Events.Fire_Starting();
            using (Eas.WebCrawler.Interfaces.TemporaryStorage storage = factory.Create(processingState)) {

                string testString = "Hello World!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!";
                byte[] bytes = new byte[] { 5, 4, 3, 2, 1 };
                using (System.IO.TextWriter writer = storage.GetTextWriter()) {
                    writer.Write(testString);
                }
                using (System.IO.TextReader reader = storage.GetTextReader()) {
                    string newString = reader.ReadToEnd();
                    Assert.AreEqual<string>(testString, newString);
                }
                using (System.IO.TextReader reader = storage.GetTextReader()) {
                    string newString = reader.ReadToEnd();
                    Assert.AreEqual<string>(testString, newString);
                }

                using (System.IO.BinaryWriter writer = storage.GetBinaryWriter()) {
                    writer.Write(bytes);
                }
                using (System.IO.BinaryReader reader = storage.GetBinaryReader()) {
                    byte[] newBytes = reader.ReadBytes(bytes.Length);
                    Assert.IsTrue(BytesAreEqual(bytes, newBytes));
                    int readCount = reader.Read(newBytes, 0, newBytes.Length);
                    Assert.AreEqual<int>(0, readCount);
                }
                using (System.IO.BinaryReader reader = storage.GetBinaryReader()) {
                    byte[] newBytes = reader.ReadBytes(bytes.Length);
                    Assert.IsTrue(BytesAreEqual(bytes, newBytes));
                    int readCount = reader.Read(newBytes, 0, newBytes.Length);
                    Assert.AreEqual<int>(0, readCount);
                }
            }
            _Context._Events.Fire_Stopped();
        }

        private bool BytesAreEqual(byte[] source, byte[] copy) {
            if (source.Length != copy.Length) return false;

            for (int i = 0; i < source.Length; i++) {
                if (source[i] != copy[i]) return false;
            }

            return true;
        }

    }
}
